<html>
 <head>
  <meta charset="UTF-8">
 </head>
 <body>
  <h1 data-lake-id="JGw3f" id="JGw3f"><span data-lake-id="ud2fecbcf" id="ud2fecbcf">典型回答</span></h1>
  <p data-lake-id="uaafe3197" id="uaafe3197"><span data-lake-id="uc808219f" id="uc808219f">​</span><br></p>
  <p data-lake-id="u5ff04417" id="u5ff04417"><span data-lake-id="u67c08b77" id="u67c08b77">TCP粘包和拆包问题是指在进行TCP通信时，因为TCP是面向流的，所以发送方在传输数据时可能会将多个小的数据包粘合在一起发送，而接收方则可能将这些数据包拆分成多个小的数据包进行接收，从而导致数据接收出现错误或者数据粘连的问题。</span></p>
  <p data-lake-id="u553f817e" id="u553f817e"><span data-lake-id="uefa96122" id="uefa96122">​</span><br></p>
  <p data-lake-id="u5268b208" id="u5268b208"><img src="https://cdn.nlark.com/yuque/0/2023/png/719664/1673082041585-1f5ab5f1-1bfc-4868-8aef-b36e6681cf5b.png?x-oss-process=image%2Fwatermark%2Ctype_d3F5LW1pY3JvaGVp%2Csize_46%2Ctext_SmF2YSA4IEd1IFA%3D%2Ccolor_FFFFFF%2Cshadow_50%2Ct_80%2Cg_se%2Cx_10%2Cy_10"></p>
  <p data-lake-id="u13600b59" id="u13600b59"><br></p>
  <p data-lake-id="udb0c623d" id="udb0c623d"><span data-lake-id="u85b04644" id="u85b04644">TCP粘包和拆包问题主要出现在以下两种情况下：</span></p>
  <ol list="u4951c99c">
   <li fid="uf16b18e1" data-lake-id="u2db3bd4d" id="u2db3bd4d"><span data-lake-id="u4b2d405e" id="u4b2d405e">发送方连续发送多个小数据包：由于TCP是基于流的协议，发送方在传输数据时可能会将多个小数据包组合成一个大数据包进行发送，从而导致接收方在接收数据时无法区分不同数据包之间的界限。</span></li>
   <li fid="uf16b18e1" data-lake-id="u34b38a62" id="u34b38a62"><span data-lake-id="u85ec216f" id="u85ec216f">接收方缓存区大小限制：接收方在接收数据时，如果接收缓存区的大小有限，可能会将一个大的数据包拆分成多个小数据包进行接收，从而导致粘包和拆包问题的出现。</span></li>
  </ol>
  <p data-lake-id="udb25f65f" id="udb25f65f"><br></p>
  <h2 data-lake-id="Y8vax" id="Y8vax"><span data-lake-id="u667db277" id="u667db277">解决方案</span></h2>
  <p data-lake-id="u894d1315" id="u894d1315" style="text-align: left"><span data-lake-id="uf280a410" id="uf280a410" class="lake-fontsize-12" style="color: rgb(25, 25, 25)">对于粘包和拆包问题，一般都是对包的格式进行约束，常见的解决方案有四种：</span></p>
  <ul list="u0b2430a1">
   <li fid="uf4c44db4" data-lake-id="u3ad43ec4" id="u3ad43ec4" style="text-align: left"><span data-lake-id="u92f57f5e" id="u92f57f5e" class="lake-fontsize-12" style="color: rgb(25, 25, 25)">将业务层协议包的长度固定下来，每个包都</span><strong><span data-lake-id="u5ac98f48" id="u5ac98f48" class="lake-fontsize-12" style="color: rgb(25, 25, 25)">固定长度</span></strong><span data-lake-id="u24304eab" id="u24304eab" class="lake-fontsize-12" style="color: rgb(25, 25, 25)">，比如512个字节大小，如果客户端发送的数据长度不足512个字节，则通过补充空格的方式补全到指定长度；</span></li>
   <li fid="uf4c44db4" data-lake-id="uc1c12337" id="uc1c12337" style="text-align: left"><span data-lake-id="u66d1fde9" id="u66d1fde9" class="lake-fontsize-12" style="color: rgb(25, 25, 25)">在每个包的末尾使用</span><strong><span data-lake-id="u1945dec7" id="u1945dec7" class="lake-fontsize-12" style="color: rgb(25, 25, 25)">固定的分隔符</span></strong><span data-lake-id="u562ff6bd" id="u562ff6bd" class="lake-fontsize-12" style="color: rgb(25, 25, 25)">，如换行符/n，如果一个包被拆分了，则等待下一个包发送过来之后找到其中的\n，然后对其拆分后的头部部分与前一个包的剩余部分进行合并即可；</span></li>
   <li fid="uf4c44db4" data-lake-id="uf8e75ad1" id="uf8e75ad1" style="text-align: left"><span data-lake-id="u264cafd6" id="u264cafd6" class="lake-fontsize-12" style="color: rgb(25, 25, 25)">仿照TCP/IP协议栈，</span><strong><span data-lake-id="u6f05c535" id="u6f05c535" class="lake-fontsize-12" style="color: rgb(25, 25, 25)">将消息分为header和body</span></strong><span data-lake-id="uced6f8f1" id="uced6f8f1" class="lake-fontsize-12" style="color: rgb(25, 25, 25)">，在head中保存有当前整个消息的长度，只有在读取到足够长度的消息之后才算是读到了一个完整的消息；</span></li>
   <li fid="uf4c44db4" data-lake-id="u7cd30995" id="u7cd30995" style="text-align: left"><span data-lake-id="u513108b1" id="u513108b1" class="lake-fontsize-12" style="color: rgb(25, 25, 25)">通过</span><strong><span data-lake-id="u09e2c300" id="u09e2c300" class="lake-fontsize-12" style="color: rgb(25, 25, 25)">自定义协议</span></strong><span data-lake-id="ucbebb271" id="ucbebb271" class="lake-fontsize-12" style="color: rgb(25, 25, 25)">进行粘包和拆包的处理。</span></li>
  </ul>
 </body>
</html>